package model

import (
	"database/sql"
	"fmt"
	"strings"
	"time"

	"github.com/tal-tech/go-zero/core/stores/cache"
	"github.com/tal-tech/go-zero/core/stores/sqlc"
	"github.com/tal-tech/go-zero/core/stores/sqlx"
	"github.com/tal-tech/go-zero/core/stringx"
	"github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx"
)

var (
	usersFieldNames          = builderx.RawFieldNames(&Users{})
	usersRows                = strings.Join(usersFieldNames, ",")
	usersRowsExpectAutoSet   = strings.Join(stringx.Remove(usersFieldNames, "`id`", "`created_time`", "`updated_time`"), ",")
	usersRowsWithPlaceHolder = strings.Join(stringx.Remove(usersFieldNames, "`id`", "`created_time`", "`updated_time`"), "=?,") + "=?"

	cacheUsersIdPrefix = "cache::users:id:"
)

type (
	UsersModel interface {
		Insert(data Users) (sql.Result, error)
		FindOne(id int64) (*Users, error)
		FindOneByUserName(username string) (*Users, error)
		FindOneByPhone(phone string) (*Users, error)
	}

	defaultUsersModel struct {
		dbconn sqlx.SqlConn
		cache  cache.CacheConf
		table  string
	}

	Users struct {
		Id          int64     `db:"id"`
		Username    string    `db:"username"`
		Password    string    `db:"password"`
		Gender      string    `db:"gender"` // 男｜女｜未公开
		Phone       string    `db:"phone"`
		Email       string    `db:"email"`
		Qq          string    `db:"qq"` // qq
		Wechat      string    `db:"wechat"`
		Status      uint8     `db:"status"` // 1-正常,2-限制使用
		CreatedTime time.Time `db:"created_time"`
		UpdatedTime time.Time `db:"updated_time"`
	}
)

func NewUsersModel(conn sqlx.SqlConn, c cache.CacheConf) UsersModel {
	return &defaultUsersModel{
		dbconn: conn,
		cache:  c,
		table:  "`users`",
	}
}

func (m *defaultUsersModel) Insert(data Users) (sql.Result, error) {
	insertsql := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?)", m.table, usersRowsExpectAutoSet)
	ret, err := m.dbconn.Exec(insertsql, data.Username, data.Password, data.Gender, data.Phone, data.Email, data.Qq, data.Wechat, data.Status)
	return ret, err
}

func (m *defaultUsersModel) FindOne(id int64) (*Users, error) {
	var resp Users

	usersIdKey := fmt.Sprintf("%s%v", cacheUsersIdPrefix, id)
	fmt.Println(usersIdKey)
	query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", usersRows, m.table)
	err := m.dbconn.QueryRow(&resp, query, id)
	fmt.Println(resp)
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *defaultUsersModel) FindOneByPhone(phone string) (*Users, error) {
	var resp Users
	query := fmt.Sprintf("select %s from %s where `phone` = ? limit 1", usersRows, m.table)
	err := m.dbconn.QueryRow(&resp, query, phone)
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *defaultUsersModel) FindOneByUserName(username string) (*Users, error) {
	var resp Users
	query := fmt.Sprintf("select %s from %s where `username` = ? limit 1", usersRows, m.table)
	err := m.dbconn.QueryRow(&resp, query, username)
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}
